#include <hls_stream.h>
#include <string.h>
//#include <stdio.h>
#include "graph_fpga.h"

#include "fpga_global_mem.h"
#include "fpga_slice.h"
#include "fpga_gather.h"
#include "fpga_filter.h"
#include "fpga_process_edge.h"
#include "fpga_cache.h"
#include "fpga_edge_prop.h"




extern "C" {
    void  readEdgesCU(
    	//uint16          *vertexScore,
    	uint16          *edges1,
    	uint16          *edges2,
		uint16          *edges3,
		uint16          *edges4,
        uint16          *tmpVertexProp,
		uint16			*csrIndex1,
		uint16			*csrIndex2,
		//uint16			*csrIndex3,
		//uint16			*csrIndex4,
		uint16			*bitMap,
#if HAVE_EDGE_PROP
        uint16          *edgeProp,
#endif
        const int           edge_end,
        const int           sink_offset,
        const int           sink_end,
		const int 			srcStart,
		const int 			srcEnd
    )

    //{
    //#include "fpga_gs_top.h"

    {
    #pragma HLS INTERFACE m_axi port=edges1 offset=slave bundle=gmem0   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=edges1 bundle=control
	#pragma HLS INTERFACE m_axi port=edges2 offset=slave bundle=gmem1   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=edges2 bundle=control
	#pragma HLS INTERFACE m_axi port=edges3 offset=slave bundle=gmem2   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=edges3 bundle=control
	#pragma HLS INTERFACE m_axi port=edges4 offset=slave bundle=gmem3   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=edges4 bundle=control

	#pragma HLS INTERFACE m_axi port=csrIndex1 offset=slave bundle=gmem4   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=csrIndex1 bundle=control
	#pragma HLS INTERFACE m_axi port=csrIndex2 offset=slave bundle=gmem5   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=csrIndex2 bundle=control
	//#pragma HLS INTERFACE m_axi port=csrIndex3 offset=slave bundle=gmem6   max_read_burst_length=32
    //#pragma HLS INTERFACE s_axilite port=csrIndex3 bundle=control
	//#pragma HLS INTERFACE m_axi port=csrIndex4 offset=slave bundle=gmem7   max_read_burst_length=32
    //#pragma HLS INTERFACE s_axilite port=csrIndex4 bundle=control

	#pragma HLS INTERFACE m_axi port=tmpVertexProp offset=slave bundle=gmem8   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=tmpVertexProp bundle=control
	#pragma HLS INTERFACE m_axi port=bitMap offset=slave bundle=gmem9   max_read_burst_length=32
    #pragma HLS INTERFACE s_axilite port=bitMap bundle=control

    #pragma HLS INTERFACE s_axilite port=edge_end       bundle=control
    #pragma HLS INTERFACE s_axilite port=sink_offset    bundle=control
    #pragma HLS INTERFACE s_axilite port=sink_end       bundle=control
	#pragma HLS INTERFACE s_axilite port=srcStart    bundle=control
    #pragma HLS INTERFACE s_axilite port=srcEnd       bundle=control
    #pragma HLS INTERFACE s_axilite port=return         bundle=control


#pragma HLS DATAFLOW


    	hls::stream<int2_token_merge>           buildArray[PE_NUM];
    	    #pragma HLS stream variable=buildArray  depth=4
    		#pragma HLS RESOURCE variable=buildArray core=FIFO_SRL


    	        hls::stream< ap_uint<8> >    writeArray[PE_NUM];
    	    #pragma HLS stream variable=writeArray  depth=4
    		#pragma HLS RESOURCE variable=writeArray core=FIFO_SRL

    	        hls::stream< ap_uint<64> >    writeArrayMerge[8];
    	    #pragma HLS stream variable=writeArrayMerge  depth=4
    	    #pragma HLS RESOURCE variable=writeArrayMerge core=FIFO_SRL


    	        hls::stream<edge_tuples_t>   edgeTuplesBuffer;
    	    #pragma HLS stream variable=edgeTuplesBuffer depth=4
    		#pragma HLS RESOURCE variable=edgeTuplesBuffer core=FIFO_SRL

    	        hls::stream<edge_tuples8_t>   edgeTuplesLevel1[8];
    	    #pragma HLS stream variable=edgeTuplesLevel1 depth=4
    	    #pragma HLS RESOURCE variable=edgeTuplesLevel1 core=FIFO_SRL

    	        hls::stream<int2_token_merge>   edgeTuplesLevel2[64];
    	    #pragma HLS stream variable=edgeTuplesLevel2 depth=4
    	    #pragma HLS RESOURCE variable=edgeTuplesLevel2 core=FIFO_SRL



        srcPropertyProcess(bitMap,csrIndex1,csrIndex2,//csrIndex3,csrIndex4,
        				edges1,edges2,edges3,edges4,
        				srcStart,srcEnd,
                        edgeTuplesBuffer
                               );
        //clearStream(edgeTuplesBuffer);

        tuplesPartition1(edgeTuplesBuffer,
        		edgeTuplesLevel1[0],
                edgeTuplesLevel1[1],
                edgeTuplesLevel1[2],
                edgeTuplesLevel1[3],
                edgeTuplesLevel1[4],
                edgeTuplesLevel1[5],
                edgeTuplesLevel1[6],
                edgeTuplesLevel1[7]);
        for(int i=0;i<8;i++){
        	#pragma HLS UNROLL
            tuplesPartition2(edgeTuplesLevel1[i],
                edgeTuplesLevel2[8*i+0],
				edgeTuplesLevel2[8*i+1],
                edgeTuplesLevel2[8*i+2],
                edgeTuplesLevel2[8*i+3],
                edgeTuplesLevel2[8*i+4],
                edgeTuplesLevel2[8*i+5],
                edgeTuplesLevel2[8*i+6],
                edgeTuplesLevel2[8*i+7]);
            }


        shuffleEntryN(edgeTuplesLevel2,buildArray);



        for(int i=0;i<PE_NUM;i++){
	#pragma HLS UNROLL
        	dstPropertyProcess(i, sink_offset, sink_end, buildArray[i], writeArray[i]);

        }

        for(int i=0;i<8;i++){
        #pragma HLS UNROLL
                	processEdgeMerge(
                	    sink_offset,
                	    sink_end,
                	    writeArray[i*8+0],
        				writeArray[i*8+1],
        				writeArray[i*8+2],
        				writeArray[i*8+3],
        				writeArray[i*8+4],
        				writeArray[i*8+5],
        				writeArray[i*8+6],
        				writeArray[i*8+7],
                		writeArrayMerge[i]
                	);
        }

        processEdgeWrite(sink_offset, sink_end, writeArrayMerge, tmpVertexProp);
    }



    //}

} // extern C

